package com.siecom.transport.bluetooth;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import com.google.protobuf.InvalidProtocolBufferException;
import com.siecom.constconfig.ConstDefine;
import com.siecom.hostservice.MainActivity;
import com.siecom.module.DeviceInterface;
import com.siecom.proto.Message;
import com.siecom.tool.ByteTool;
import com.siecom.tool.CRC16Algorithm;
import com.siecom.tool.LogUtil;
import com.siecom.tool.MacUtils;
import com.siecom.tool.SingletonThreadPool;
import com.siecom.transport.CommServer;
import com.siecom.transport.SiecomDevice;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.crypto.Mac;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.annotations.NonNull;
import io.reactivex.schedulers.Schedulers;

import static android.content.Context.MODE_PRIVATE;


/**
 * Created on 2016/6/13.
 */

public class BlueServer extends CommServer {
    public static final String PROTOCOL_UUID = "00001101-0000-1000-8000-00805F9B34FB";
    public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
    public static final String TAG = BlueServer.class.getSimpleName();
    private static BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    private static BluetoothServerSocket serverSocket = null;
    private static volatile BluetoothSocket socket = null;
    private static volatile InputStream inputStream = null;
    private static volatile OutputStream outputStream = null;

    private volatile boolean isAccept = true;

    @SuppressLint("MissingPermission")
    public BlueServer() {

        if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
        }

    }

    public static String getBlueName() {
        Context ctx = MainActivity.context;
        SharedPreferences sp = ctx.getSharedPreferences(ConstDefine.SP_FILE_NAME, MODE_PRIVATE);
//        SharedPreferences.Editor editor = sp.edit();
//        editor.putString(ConstDefine.SP_KEY_BLUE_NAME,"");
//        editor.commit();
        String blueName = sp.getString(ConstDefine.SP_KEY_BLUE_NAME,"");

        LogUtil.e(TAG,"要修改的蓝牙名称是：" + blueName);
        if(!TextUtils.isEmpty(blueName)){
            return blueName;
        }
        String mac = null;
        for (int i = 0; i < 3; i++) {
//            mac = DeviceInterface.getDeviceId();
//            mac = MacUtils.getMac();
            mac = getBTAddress(); //
            mac = mac.replaceAll(":","");
            Log.e("MAC", mac + "==");
            if (mac != null) {
                break;
            }
            if (i == 2) {
                return null;
            }
            SystemClock.sleep(100);
        }
        byte[] addre = ByteTool.hexStr2Bytes(mac);
        int crc16 = CRC16Algorithm.calcCrc16(addre);
        String crcStr;
        if(crc16 < 10000){
            crcStr = String.format("%05d",crc16);
        }else {
            crcStr = String.valueOf(crc16);
        }
        return ConstDefine.BLUE_NAME_PRE + crcStr;
    }

    public static String getBTAddress() {

//        String address = MacUtils.getMac();
//        LogUtil.e(TAG,"blue address:" + address);
//        String blueName = mBluetoothAdapter.getName();
//        LogUtil.e(TAG,"blue name:" + blueName);
        String blueMac = MacUtils.getBtAddressViaReflection();
        LogUtil.e(TAG,"blue mac==" + blueMac);
        DeviceInterface.setKeyValue(ConstDefine.SP_KEY_BLUE_Device_ID,blueMac);
        return blueMac;
    }

    public void setDiscoverableTimeout(int timeout) {
        BluetoothAdapter adapter = mBluetoothAdapter;
        String id = getBlueName();
        LogUtil.e(TAG,"getBlueName=" + id);
        if (null == id) {
            SystemClock.sleep(500);
            id = getBlueName();
            LogUtil.e(TAG,"第二次 getBlueName=" + id);
        }
        adapter.setName(id);
        MainActivity.showBlueName( id);
        try {
            Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
            setDiscoverableTimeout.setAccessible(true);
            Method setScanMode = BluetoothAdapter.class.getMethod("setScanMode", int.class, int.class);
            setScanMode.setAccessible(true);

            setDiscoverableTimeout.invoke(adapter, timeout);
            setScanMode.invoke(adapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, timeout);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void closeDiscoverableTimeout() {
        BluetoothAdapter adapter = mBluetoothAdapter;
        try {
            Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
            setDiscoverableTimeout.setAccessible(true);
            Method setScanMode = BluetoothAdapter.class.getMethod("setScanMode", int.class, int.class);
            setScanMode.setAccessible(true);

            setDiscoverableTimeout.invoke(adapter, 1);
            setScanMode.invoke(adapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE, 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static String getName() {

        return mBluetoothAdapter.getName();
    }

    public static String getAddress() {
//        return mBluetoothAdapter.getAddress();
        return MacUtils.getMac();
    }


    public Observable<BluetoothSocket> accept() {
        if (isAccept) {
            isAccept = false;
        }
        return Observable.create(new ObservableOnSubscribe<BluetoothSocket>() {
            @SuppressLint("MissingPermission")
            @Override
            public void subscribe(@NonNull ObservableEmitter<BluetoothSocket> observableEmitter) throws Exception {
                synchronized (this) {

                    for (int i = 0; i < 60; i++) {
                        try {

                            close();
                            SystemClock.sleep(10);
                            serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM, UUID.fromString(PROTOCOL_UUID));
                            Log.e(TAG, "wait cilent connect...");
                            isAccept = true;
                            DeviceInterface.showToast("蓝牙正常启动");
                            break;
                        } catch (IOException e) {
                            e.printStackTrace();
                            if (i == 59) {
                                observableEmitter.onError(e);
                            }
                            SystemClock.sleep(500);
                            isAccept = false;
                            continue;
                        }

                    }


                    while (isAccept) {
                        setDiscoverableTimeout(3000000);
                        if (serverSocket != null) {
                            try {
                                socket = serverSocket.accept();
                                Log.d(TAG, "accept success !");
                            } catch (InvalidProtocolBufferException ex) {
                                ex.printStackTrace();
                                continue;
                            } catch (IOException e) {
                                e.printStackTrace();
                                continue;
                            }
                            inputStream = socket.getInputStream();
                            outputStream = socket.getOutputStream();
                            observableEmitter.onNext(socket);
                            closeDiscoverableTimeout();
                            SystemClock.sleep(1);
                        }
                    }

                    observableEmitter.onComplete();


                }
            }

        }).subscribeOn(Schedulers.io());

    }
    public static final ExecutorService service = Executors.newSingleThreadExecutor();
    int totalLen = 0;
    ArrayList mByteArray = new ArrayList<Byte>();
    public Observable<Message.siecomproto> listen() {
        isInterrupted = false;
        return Observable.create(new ObservableOnSubscribe<Message.siecomproto>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Message.siecomproto> observableEmitter) throws Exception {
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        synchronized (this) {
                            LogUtil.e(TAG,"当前线程：" + Thread.currentThread().getName());
                            while (!isInterrupted) {
                                try {
                                    int len = inputStream.available();
                                    if(len > 0){
                                        totalLen += len;
                                        byte[] b = new byte[len];
                                        LogUtil.e(TAG,"接收到的数据len：" + len + " -- totalLen = " + totalLen);
                                        LogUtil.e(TAG,"b.length = " + b.length);
                                        inputStream.read(b,0,len);
                                        LogUtil.e(TAG,"收到的数据：" + ByteTool.byte2hex(b));
                                        for(int j = 0; j< len;j++){
                                            mByteArray.add(b[j]);
                                        }
                                        LogUtil.e(TAG,"mByteArray.size = " + mByteArray.size());
                                        LogUtil.e(TAG,"totalLen = " + totalLen);
                                        byte[] sendByte = new byte[totalLen];
                                        for(int m = 0;m < totalLen; m++){
                                            sendByte[m] = (byte)mByteArray.get(m);
                                        }

                                        LogUtil.e(TAG,"接收到的数据byte：" + ByteTool.byte2hex(sendByte));
                                        Message.siecomproto msg = Message.siecomproto.parseFrom(sendByte);
                                        totalLen = 0;
                                        mByteArray.clear();
                                        LogUtil.e(TAG,"接收到的数据msg：" + msg.toString() + "--length==" + sendByte.length);
                                        observableEmitter.onNext(msg);
                                    }

                                } catch (InvalidProtocolBufferException ex) {
                                    ex.printStackTrace();
                                    LogUtil.e(TAG,"InvalidProtocolBufferException");
    //                            totalLen = 0;
    //                            mByteArray.clear();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    LogUtil.e(TAG,"IOException :" + e.getMessage());
//                        observableEmitter.onError(e);
                                    totalLen = 0;
                                    mByteArray.clear();
                                    SystemClock.sleep(3);
                                    break;
                                }catch (IndexOutOfBoundsException e){
                                    LogUtil.e(TAG,"IndexOutOfBoundsException :" + e.getMessage());
                                    totalLen = 0;
                                    mByteArray.clear();
//                            break;
                                }
                                try {
                                    Thread.sleep(10);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            // 0键盘  1指纹 2IC卡  3磁条卡  4蓝牙 5 身份证
//                    MainActivity.getmSys().DLL_SysLedControl((byte) 4,(byte)0);
                            LogUtil.e(TAG,"连接--------------------------------------");
//                    try {
//                        synchronized (this) {
//                            if (inputStream != null)
//                                inputStream.close();
//                            inputStream = null;
//                            if (outputStream != null)
//                                outputStream.close();
//                            outputStream = null;
//                            if (socket != null)
//                                socket.close();
//                            socket = null;
//                        }
//                    } catch (IOException e) {
//                        e.printStackTrace();
//
//                    }
//                    observableEmitter.onComplete();
                        }
                    }
                });

            }
        }).subscribeOn(Schedulers.io());
    }

    @Override
    public void close() {
        isInterrupted = true;
        isAccept = false;
        SystemClock.sleep(300);
        try {
            synchronized (this) {
                if (serverSocket != null) {
                    serverSocket.close();
                    serverSocket = null;
                }
                if (inputStream != null)
                    inputStream.close();
                inputStream = null;
                if (outputStream != null)
                    outputStream.close();
                outputStream = null;
                if (socket != null)
                    socket.close();
                socket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    @Override
    public void sendToRemote(Message.siecomproto msg) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                LogUtil.e(TAG,msg.toString());
                LogUtil.e(TAG,"sendToRemote 长度：" + msg.toByteArray().length);
                synchronized (this) {
                    try {
                        while (inputStream.available() > 0){
                            inputStream.read();
                        }
                        if(null == outputStream){
                            outputStream = socket.getOutputStream();
                        }
                        msg.writeTo(outputStream);
                        outputStream.flush();
                    } catch (IOException e) {
                        e.printStackTrace();

                    }
                }
            }
        };
        singleThreadExecutor.submit(runnable);

    }

}
